//
//  KZNetBase.swift
//  KZSwiftMoudel
//
//  Created by 朱凯 on 2018/5/9.
//  Copyright © 2018年 JooKey. All rights reserved.
//

import Foundation

import Alamofire


/// 对原始参数加密
///
/// - Parameters:
///   - type: 请求类型(是一个自定义的枚举)
///   - originParams: 原始参数
/// - Returns: 最终用于请求的参数
func makeFinialParams(api: KZNetApi,
                      originParams: Dictionary<String, Any>) -> Dictionary<String, Any> {
    
    // 请求类型
    let apiType = api.apiType
    // 请求版本
    let apiVersion = "\(api.apiVersion)"
    // 随机数
    let rand = random(in: 0...1000)
    // 当前时间戳
    let time = NSDate().timeIntervalSince1970.int
    // 请求id
    let requestID = "\(time)\(rand)"
    // app版本参数拼接
    let shortVersion = Bundle.main.infoDictionary!["CFBundleShortVersionString"]
    let bundleVersion = Bundle.main.infoDictionary!["CFBundleVersion"]
    let appVersion = "\(shortVersion!).\(bundleVersion!)"
    let versionComponents = appVersion.components(separatedBy: ".") 
    let versionNumber = versionComponents[0].intValue * 10000 + versionComponents[1].intValue * 100 + versionComponents[2].intValue * 1
    // 原始参数加密
    let dataStr = ByCoreCrypt.encryptString(originParams)!
    
    // 新的参数列表
    var dic = [
        "time"          : "\(time)",
        "alg"           : "md5",
        "data"          : dataStr,
        "type"          : apiType,
        "notify_id"     : requestID,
        "api_ver"       : apiVersion,
        "app_type"      : "ios",
        "app_version"   : "\(versionNumber)",
        ]
    
    // 对新参数列表签名，并把签名添加到新参数列表中
    let signStr = ByCoreCrypt.signData(dic)
    dic["sign"] = signStr
    
    // 对新参数列表再一次加密，生成最终的参数列表并返回
    var crypt = ""
    if let jsonData = try? JSONSerialization.data(withJSONObject: dic, options: []) {
        if let jsonStr = String.init(data: jsonData, encoding: .utf8) {
            crypt = ByCoreCryptDes.desEncode(jsonStr, client_secret)
        }
    }
    let finialParams = ["itboye": crypt]
    return finialParams
}


/// 基础的请求方法
///
/// - Parameters:
///   - type: 请求类型(是一个自定义的枚举)
///   - originParams: 原始参数
///   - resultClouse: 异步回调结果
func KZNetBaseRequest(api: KZNetApi,
                      params: Dictionary<String, Any>,
                      resultClouse: @escaping ((KZNetResult)->Void)) {
    
    let finialParmas = makeFinialParams(api: api, originParams: params)
    
    request(api, method: .post, parameters: finialParmas).responseJSON { (res: DataResponse) in

        var code = -1
        var data: Any = "not init"
        var tag = KZNetResult.Tag.failure("是未处理的结果")
        
        var result = KZNetResult(tag: tag, code: code, data: data)
        
        // 返回的服务器响应存在error
        if let error = res.error {
            tag = KZNetResult.Tag.failure(error.localizedDescription)
            result.tag = tag
            resultClouse(result)
            return
        }
        // 返回的服务器响应数据为空
        if res.value == nil {
            tag = KZNetResult.Tag.failure("数据为空")
            result.tag = tag
            resultClouse(result)
            return
        }
        // json字典(未解码的)
        guard let jsonDic = res.value as? Dictionary<String, Any> else {
            tag = KZNetResult.Tag.failure("原始返回数据不为字典")
            result.tag = tag
            resultClouse(result)
            return
        }
        // 获得未解码的data
        guard let dataStr = jsonDic["data"] as? String else {
            tag = KZNetResult.Tag.failure("无法获得未解码字符串数据")
            result.tag = tag
            resultClouse(result)
            return
        }
        
        // 对未解码的data进行解码
        guard let dataDic = ByCoreCrypt.decryptString(dataStr) as? Dictionary<String, Any> else {
            tag = KZNetResult.Tag.failure("无法解码返回数据")
            result.tag = tag
            resultClouse(result)
            return
        }

        code = dataDic["code"] as! Int
        data = dataDic["data"]!
        result.code = code
        result.data = data
        
        
        if code == 0 {
            // 判断返回数据和我们需要的数据是否一致
            switch api.apiExpectedDataType {
            case .dictionary:
                if !(data is Dictionary<String, Any>) {
                    tag = KZNetResult.Tag.failure("期望返回数据为字典而实际是\(type(of: data))")
                    result.tag = tag
                    resultClouse(result)
                    return
                }
            case .array:
                if !(data is Array<Any>) {
                    tag = KZNetResult.Tag.failure("期望返回数据为数组而实际是\(type(of: data))")
                    result.tag = tag
                    resultClouse(result)
                    return
                }
            case .string:
                if !(data is String) {
                    tag = KZNetResult.Tag.failure("期望返回数据为字符串而实际是\(type(of: data))")
                    result.tag = tag
                    resultClouse(result)
                    return
                }
            }
            tag = KZNetResult.Tag.success
        } else {
            tag = KZNetResult.Tag.failure("\(data)")
        }
        result.tag = tag
        resultClouse(result)
    }


}




